<template>
    <div class="l7-map">
        <div :id="mapId" class="map-container" ref="mapRef"></div>
    </div>
</template>

<script setup lang="ts">
import { Scene, Map, MouseLocation, ExportImage, Scale, Fullscreen, Zoom, Mapbox, Control } from '@antv/l7'
import { ControlEvent, DrawCircle, DrawControl, DrawLine, DrawPoint, DrawPolygon } from '@antv/l7-draw';
import mapboxgl from 'mapbox-gl'
import type { StyleSpecification, Map as MapboxMap } from 'mapbox-gl';
// import { defaultGisStyle } from '/@/const/gisStyle'
import { useTemplateRef } from 'vue'
import { myThrottle } from '@/utils/debounce';

// Props
const {
    mapId = 'l7-map',
    accessToken = 'mapbox_access_token',
    options = {},
    autoInit = true,
    showLocation = true,
    exportImage = false,
    showScale = true,
    showFullScreen = false,
    showZoom = true,
    showDraw = false,
    showGoBack = false,
    flyAnimate = true
} = defineProps<{
    mapId: string,  // 容器唯一id 必传
    accessToken?: string,  // mapbox token
    options?: object, // mapbox 配置
    autoInit?: boolean, // 是否立即初始化
    showLocation?: boolean, // 右下角展示自带的经纬度
    exportImage?: boolean, // 导出图片按钮
    showScale?: boolean, // 缩放尺 该控件用于显示地图上的距离与地面上相应距离的比率
    showFullScreen?: boolean, // 全屏按钮
    showZoom?: boolean, // 缩放层级
    showDraw?: boolean, // 绘制控件
    showGoBack?: boolean, // 回到原中心点按钮
    flyAnimate?: boolean // 飞行动画
}>();

// 事件
const emits = defineEmits(['loaded', 'style-loaded', 'draw-added'])

const mapRef = useTemplateRef('mapRef')

// 地图在隐藏时 屏幕尺寸改变时的监听
const hiddenObserver = () => {
    const observer = new ResizeObserver(myThrottle(() => {
        scene?.map.resize();
        console.log('hiddenObserver')
    }, 1000))
    if (mapRef.value) {
        observer.observe(mapRef.value)
    }
    onBeforeUnmount(() => {
        if (mapRef.value) {
            observer.unobserve(mapRef.value)
        }
    })
}

const defaultGisStyle: StyleSpecification = {
    version: 8,
    sources: {
        m_mono: {
            type: 'raster',
            // tiles: ['/tile/{z}/{x}/{y}.png'],
            tiles: ['/tile/{z}/{x}/{y}.jpg'],

            tileSize: 256,
            attribution: '',
        },
    },
    glyphs: '../../static/glyphs/{fontstack}/{range}.pbf',
    layers: [
        {
            id: 'm_mono',
            type: 'raster',
            source: 'm_mono',
            minzoom: 0,
            maxzoom: 18,
        },
    ],
};

// 定义默认Options选项
const defaultOptions: mapboxgl.MapOptions | any = computed(() => {
    return {
        container: mapId,
        style: defaultGisStyle,
        center: [110.2191, 33.2202],
        zoom: 2.2,
        minZoom: 1,
        maxZoom: 20,
        antialias: true,
        pitch: 0,
        projection: '',
        performanceMetricsCollection: false,
        preserveDrawingBuffer: exportImage,
    };
})

interface MyScene extends Scene {
    map: MapboxMap
}
// 创建场景实例
let scene: MyScene | null

// 创建地图实例
let map: MapboxMap | null

// 初始化地图
const initMap = () => {
    mapboxgl.accessToken = accessToken

    //是否支持webgl
    if (!mapboxgl.supported()) {
        console.warn('当前浏览器不支持WebGL')
        throw new Error('当前浏览器不支持WebGL')
    }

    // 创建mapbox地图实例
    const mapbox = new mapboxgl.Map({
        ...defaultOptions.value,
        ...options,
    });

    // 创建l7场景实例
    scene = new Scene({
        id: mapId,
        map: new Mapbox({
            mapInstance: mapbox,
        }),
        logoVisible: false,
    }) as MyScene

    // 获取地图实例
    map = scene.map


    // 加载默认样式完成
    scene.on('style.load', () => {
        // 默认背景样式
        scene?.map.setFog({
            color: "rgb(186, 210, 235)",
            "high-color": "rgb(36, 92, 223)",
            "horizon-blend": 0.02,
            "space-color": "rgb(11, 11 ,25)",
            "star-intensity": 0.6,
        });

        emits('style-loaded', scene)
    })

    // 加载完成
    scene.on('loaded', () => {
        console.log('L7 Map loaded')

        showLocation && scene?.addControl(new MouseLocation({ position: 'bottomright' }))

        exportImage && scene?.addControl(new ExportImage({ onExport: (base64: string) => { download(base64) } }))

        showScale && scene?.addControl(new Scale());

        showFullScreen && scene?.addControl(new Fullscreen());

        showZoom && scene?.addControl(new Zoom({ position: 'topleft', showZoom: true }));

        if (showDraw) {
            /**
            * 绘图控件对象
            getActiveType	获取当前激活的绘制类型	() => DrawType | null
            setActiveType	设置当前激活的绘制类型，若当前传入的绘制类型已经激活则会取消激活	(DrawType | null) => void
            getDrawData	获取绘制数据	() => Record<DrawType, Feature[]>
            getTypeDraw	获取参数类型对应的 Draw	(type: DrawType) => Draw | null
            clearDrawData	清除绘制数据
            example:drawControl.getDrawData()
            */
            // 显示绘制距离
            const distanceOptions = {
                showTotalDistance: false,
                showDashDistance: true,
                format: (meters: number) => {
                    if (meters >= 1000) {
                        return +(meters / 1000).toFixed(2) + 'km';
                    } else {
                        return +meters.toFixed(2) + 'm';
                    }
                },
            };

            const drawControl = new DrawControl(scene as MyScene, {
                drawConfig: {
                    point: {
                        distanceOptions
                    },
                    line: {
                        distanceOptions
                    },
                    polygon: {
                        distanceOptions,
                    },
                    rect: {
                        distanceOptions
                    },
                    circle: {
                        distanceOptions: {
                            ...distanceOptions,
                            // format: (meters: number) => {
                            //     return ''
                            // },
                        }
                    },
                    clear: true
                }
            });
            scene?.addControl(drawControl);
            drawControl.on(ControlEvent.DrawChange, (changeType) => {
                console.log(changeType);
            });
            emits('draw-added', drawControl)
        }

        if (showGoBack) {
            // 回到原中心点
            const goBack = new Control({
                position: 'topright',
            });
            goBack.onAdd = function () {
                let el = document.createElement('button');
                el.onclick = () => {
                    map?.flyTo(
                        {
                            // @ts-ignore
                            center: options.center || defaultOptions.value.center,
                            // @ts-ignore
                            zoom: options.zoom || defaultOptions.value.zoom,
                            // @ts-ignore
                            pitch: options.pitch || defaultOptions.value.pitch,
                            // 是否开启飞行动画
                            animate: flyAnimate,
                            // 地图绕垂直轴（Z轴）顺时针旋转的角度（单位：度）
                            // bearing: 0,
                            // duration: 1000,
                            // easing: t => Math.pow(t, 3) + 0.5 * Math.sin(t * 10), // 自定义弹性+震荡
                        }
                    )
                }
                el.title = '回到原中心点'
                el.className = 'l7-goback l7-button-control';
                // svg图标
                el.innerHTML = `<svg class="l7-iconfont" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 100 100"><!-- Icon from Font-GIS by Jean-Marc Viglino - https://github.com/Viglino/font-gis/blob/main/LICENSE-CC-BY.md --><path fill="currentColor" d="M43 0v13.166C27.944 16.03 16.03 27.944 13.166 43H0v14h13.166C16.03 72.056 27.944 83.97 43 86.834V100h14V86.834C72.056 83.97 83.97 72.056 86.834 57H100V43H86.834C83.97 27.944 72.056 16.03 57 13.166V0zm7 22.5A27.425 27.425 0 0 1 77.5 50A27.425 27.425 0 0 1 50 77.5A27.425 27.425 0 0 1 22.5 50A27.425 27.425 0 0 1 50 22.5" color="currentColor"/><circle cx="50" cy="50" r="15" fill="currentColor" color="currentColor"/></svg>`
                return el;
            };
            scene?.addControl(goBack)
        }

        emits('loaded', scene, map)
    })

    // 屏幕改变自适应
    scene.on('resize', () => {
        console.log('scene resize')
        scene?.map.resize();
    })

    // 注册全局图片
    // scene.addImage('icon', '/assets/icon/iJcz.png')

    // .....
}

const download = (base64: string, filename: string = 'export.png') => {
    // 创建隐藏的 <a> 元素
    const link = document.createElement('a');

    // 组合完整的 Data URL（若 base64 未包含 MIME 类型则自动补全）
    const dataUrl = base64.startsWith('data:')
        ? base64
        : `data:image/png;base64,${base64}`;

    // 设置下载链接属性
    link.href = dataUrl;
    link.download = filename;  // 自定义文件名
    link.style.display = 'none';

    // 插入 DOM 并模拟点击
    document.body.appendChild(link);
    link.click();

    // 清理 DOM
    document.body.removeChild(link);
};

// 暴露场景实例
defineExpose({
    // @ts-ignore
    scene,
    initMap
})

onMounted(() => {
    if (!autoInit) {
        return
    }
    initMap()
    hiddenObserver()
})

onUnmounted(() => {
    map?.remove()
    map = null
    // scene?.destroy()
    scene = null
})
</script>


<style lang="less" scoped>
.l7-map {
    position: relative;
    height: 100%;
    width: 100%;
    overflow: hidden;
    color: #000;

    .map-container {
        height: 100%;
        width: 100%;
    }
}
</style>